﻿using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.Receiving;
using MQTTnet.Protocol;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Model;
using BLL;
using System.Web.Script.Serialization;

namespace MQTT服务端
{
    public partial class ClientFrm : Form
    {
        Timer timer = new Timer();
        JavaScriptSerializer Serializer = new JavaScriptSerializer();
        BContentToSqlServer bts = new BContentToSqlServer();
        public ClientFrm()
        {
            InitializeComponent();
            timer.Interval = 500;
            timer.Tick += Timer_Tick;
            timer.Start();
            InitSetting();
        }
        private void Timer_Tick(object sender, EventArgs e)
        {
            toolStripStatusDateTime.Text = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
        }
        void InitSetting()
        {
            //获取本机所有的IP4地址
            //string[] ips = Dns.GetHostAddresses(Environment.MachineName).Where(item => !item.IsIPv6LinkLocal).Select(item => item.ToString()).ToArray();
            comboIp_List.Text = "192.168.60.65";
            txtPort.Text = "8000";
            txtUserName.Text = "sa";
            txtPwd.Text = "1";
            comboQoS.DataSource = Enum.GetNames(typeof(MQTTnet.Protocol.MqttQualityOfServiceLevel));
        }
        IMqttClient client;
        private void btnConnect_Click(object sender, EventArgs e)
        {
            //  txtClientId.Text = Guid.NewGuid().ToString();
            ConnectMqttServer();
        }

        private void ConnectMqttServer()
        {
            if (string.IsNullOrEmpty(txtClientId.Text.Trim()))
            {
                MessageBox.Show("ClientId不能为空！");
                return;
            }
            if (btnConnect.Text.Equals("连接"))
            {
                client = new MqttFactory().CreateMqttClient();
                MqttClientOptionsBuilder builder = new MqttClientOptionsBuilder()
                       .WithClientId(txtClientId.Text.Trim())
                       .WithCommunicationTimeout(TimeSpan.FromMilliseconds(50000))
                       .WithTcpServer("192.168.60.65", Convert.ToInt32(txtPort.Text.Trim()));
                if (ck_UserPwd.Checked)
                {
                    builder.WithCredentials(txtUserName.Text.Trim(), txtPwd.Text.Trim());
                }
                IMqttClientOptions option = builder.Build();
                //消息接收事件
                client.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(Client_ApplicationMessageReceivedAsync);
                //客户端连接事件
                client.ConnectedHandler = new MqttClientConnectedHandlerDelegate(Client_ConnectedAsync);
                // client.UseConnectedHandler
                //客户端连接断开事件
                client.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(Client_DisconnectedAsync);

                client.ConnectAsync(option);

            }
            else
            {
                client.DisconnectAsync().Wait();
                UpdateStatus(client.IsConnected);
                client.Dispose();
            }
        }
        private Task Client_DisconnectedAsync(MqttClientDisconnectedEventArgs arg)
        {
            //客户端断开事件
            string msg = $" 断开连接, 返回结果：{arg.Reason}";
            AddLog(1, msg);
            UpdateStatus(client.IsConnected);
            return Task.FromResult(arg);
        }
        private Task Client_ConnectedAsync(MqttClientConnectedEventArgs arg)
        {
            //客户端连接事件
            string msg = $"客户端ID 连接,结果:{arg.ConnectResult.ResultCode}";
            AddLog(0, msg);
            UpdateStatus(client.IsConnected);
            
            return Task.FromResult(arg);
        }
        private Task Client_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
        {
            //客户端取消订阅事件
            string msg = $"消息ClientId：[{arg.ClientId}] , topic:[{arg.ApplicationMessage.Topic}], 内容:[{arg.ApplicationMessage.ConvertPayloadToString()}],QoS:[{arg.ApplicationMessage.QualityOfServiceLevel}]";
            AddLog(1, msg);
            return Task.FromResult(arg);
        }
        private void ck_UserPwd_CheckedChanged(object sender, EventArgs e)
        {
            txtUserName.Enabled = txtPwd.Enabled = ck_UserPwd.Checked;
        }
        void AddLog(int cate, string msg)
        {
            this.Invoke(new Action(() =>
            {
                ListViewItem item = new ListViewItem();
                item.ImageIndex = cate;
                item.SubItems.Add(DateTime.Now.ToString("HH:mm:ss"));
                item.SubItems.Add(msg);
                lstview_Note.Items.Add(item);
                lstview_Note.EnsureVisible(lstview_Note.Items.Count - 1);
            }));
        }
        private async void btnSubscribed_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtTopic.Text))
            {
                MessageBox.Show("主题不能为空！");
                return;
            }
            //主题订阅
            if (client?.IsConnected == true)
            {
                //QoS0 （Almost One）：至多一次，只发送一次，会发生消息丢失或重复。
                //QoS1(Atleast Once): 至少一次，确保消息到达，但消息可能重复发送
                //QoS2（Exactly Once）:只有一次：只有一次，确保消息只到达一次。
                var result = await client.SubscribeAsync(new MqttTopicFilter()
                {
                    QualityOfServiceLevel = (MqttQualityOfServiceLevel)Enum.Parse(typeof(MqttQualityOfServiceLevel), comboQoS.Text.Trim()),
                    Topic = txtTopic.Text.Trim()
                });
                StringBuilder sb = new StringBuilder();
                foreach (var item in result.Items)
                {
                    sb.AppendLine($"订阅主题:[{item.TopicFilter.Topic}],QoS:[{item.TopicFilter.QualityOfServiceLevel}],ReturnCode:[{item.ResultCode}]");
                }
                AddLog(0, sb.ToString());
            }
            else
            {
                MessageBox.Show("请先连接服务！");
            }
        }
        private async void btnPublish_Click(object sender, EventArgs e)
        {

        }
        void UpdateStatus(bool isConnected)
        {
            this.Invoke(new Action(() =>
            {
                if (!isConnected)
                {
                    btnConnect.Text = "连接";
                    btnConnect.BackColor = Color.Red;
                    comboIp_List.Enabled = txtPort.Enabled = true;
                }
                else
                {
                    btnConnect.Text = "断开";
                    btnConnect.BackColor = Color.Green;
                    comboIp_List.Enabled = txtPort.Enabled = false;
                }
            }));
          
        }

        private async void btnUnsubscribed_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtTopic.Text))
            {
                MessageBox.Show("主题不能为空！");
                return;
            }
            //主题订阅
            if (client?.IsConnected == true)
            {
                //QoS0 （Almost One）：至多一次，只发送一次，会发生消息丢失或重复。
                //QoS1(Atleast Once): 至少一次，确保消息到达，但消息可能重复发送
                //QoS2（Exactly Once）:只有一次：只有一次，确保消息只到达一次。
                var result = await client.UnsubscribeAsync(txtTopic.Text.Trim());
              
                StringBuilder sb = new StringBuilder();
                foreach (var item in result.Items)
                {
                    sb.AppendLine($"取消主题:[{item.TopicFilter}]订阅,ReturnCode:[{item.ReasonCode}]");
                }
                AddLog(0, sb.ToString());
            }
            else
            {
                MessageBox.Show("请先连接服务！");
            }
        }

        private void txtClientId_TextChanged(object sender, EventArgs e)
        {

        }

        public async void timer1_Tick(object sender, EventArgs e)
        {
            try
            {
                txtMsgTopic.Text = "CNCMachineState";
                List<MMachineStateCNC> mscnc = new List<MMachineStateCNC>();
                mscnc = bts.GetMachineStateDataByCNC();
                var content = Serializer.Serialize(mscnc);
                txtMsgContent.Text = content;

                var result = await client.PublishAsync(new MqttApplicationMessage
                {
                    Topic = txtMsgTopic.Text.Trim(),
                    QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce,
                    Payload = Encoding.UTF8.GetBytes(txtMsgContent.Text.Trim())
                });
                string msg = $"发布消息：{txtMsgContent.Text} Topic:{txtMsgTopic.Text.Trim()} 结果:{result.ReasonCode}";
                AddLog(0, msg);

                txtMsgTopic.Text = "CNCMachineCapactiy";
                List<MMachineCapactiyCNC> mcc = new List<MMachineCapactiyCNC>();
                mcc = bts.GetMachineCapactiyDataByCNC();
                content = Serializer.Serialize(mcc);
                txtMsgContent.Text = content;
                result = await client.PublishAsync(new MqttApplicationMessage
                {
                    Topic = txtMsgTopic.Text.Trim(),
                    QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce,
                    Payload = Encoding.UTF8.GetBytes(txtMsgContent.Text.Trim())
                });
                msg = $"发布消息：{txtMsgContent.Text} Topic:{txtMsgTopic.Text.Trim()} 结果:{result.ReasonCode}";
                AddLog(0, msg);

                //执行序号
                txtMsgTopic.Text = "CNCMachineProgram";
                List<MMachineProgram> cncprogram = new List<MMachineProgram>();
                cncprogram = bts.GetMachineProgramDataByCNC();
                content = Serializer.Serialize(cncprogram);
                txtMsgContent.Text = content;
                result = await client.PublishAsync(new MqttApplicationMessage
                {
                    Topic = txtMsgTopic.Text.Trim(),
                    QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce,
                    Payload = Encoding.UTF8.GetBytes(txtMsgContent.Text.Trim())
                });
                msg = $"发布消息：{txtMsgContent.Text} Topic:{txtMsgTopic.Text.Trim()} 结果:{result.ReasonCode}";
                AddLog(0, msg);

                //
                txtMsgTopic.Text = "CNCMachinePressure";
                List<MMachinePressure> cncpressure = new List<MMachinePressure>();
                cncpressure = bts.GetMachinePressureDataByCNC();
                content = Serializer.Serialize(cncpressure);
                txtMsgContent.Text = content;
                result = await client.PublishAsync(new MqttApplicationMessage
                {
                    Topic = txtMsgTopic.Text.Trim(),
                    QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce,
                    Payload = Encoding.UTF8.GetBytes(txtMsgContent.Text.Trim())
                });
                msg = $"发布消息：{txtMsgContent.Text} Topic:{txtMsgTopic.Text.Trim()} 结果:{result.ReasonCode}";
                AddLog(0, msg);

                //
                txtMsgTopic.Text = "CNCMachinetemperature";
                List<MMachinetemperature> cnctemperature = new List<MMachinetemperature>();
                cnctemperature = bts.GetMachinetemperatureDataByCNC();
                content = Serializer.Serialize(cnctemperature);
                txtMsgContent.Text = content;
                result = await client.PublishAsync(new MqttApplicationMessage
                {
                    Topic = txtMsgTopic.Text.Trim(),
                    QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce,
                    Payload = Encoding.UTF8.GetBytes(txtMsgContent.Text.Trim())
                });
                msg = $"发布消息：{txtMsgContent.Text} Topic:{txtMsgTopic.Text.Trim()} 结果:{result.ReasonCode}";
                AddLog(0, msg);

                txtMsgTopic.Text = "CNCMachineAlarm";
                List<MMachineAlarmCNC> cncalarm = new List<MMachineAlarmCNC>();
                cncalarm = bts.GetMachineAlarmDataByCNC();
                content = Serializer.Serialize(cncalarm);
                txtMsgContent.Text = content;
                result = await client.PublishAsync(new MqttApplicationMessage
                {
                    Topic = txtMsgTopic.Text.Trim(),
                    QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce,
                    Payload = Encoding.UTF8.GetBytes(txtMsgContent.Text.Trim())
                });
                msg = $"发布消息：{txtMsgContent.Text} Topic:{txtMsgTopic.Text.Trim()} 结果:{result.ReasonCode}";
                AddLog(0, msg);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }


        }

        private void splitContainer1_Panel1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void ClientFrm_Load(object sender, EventArgs e)
        {
            txtClientId.Text = "CNC-CNC";
        }

        private void splitContainer2_Panel1_Paint(object sender, PaintEventArgs e)
        {

        }
    }
}
